using System.IO;
using System.Text;
using System.Xml.Linq;
using Engine.OldSerialization;

namespace RuthlessConquest {
    public class GameState {
        public class Serializer : ISerializer<GameState> {
            public void Serialize(InputArchive archive, ref GameState value) {
                value = new GameState();
                archive.Serialize("StepIndex", ref value.StepIndex);
                archive.Serialize("Data", ref value.Data);
            }

            public void Serialize(OutputArchive archive, GameState value) {
                archive.Serialize("StepIndex", value.StepIndex);
                archive.Serialize("Data", value.Data);
            }
        }

        public int StepIndex;

        public object Data;

        public uint CalculateHash() {
            if (Data is string) {
                return Crc32.ComputeChecksum(Encoding.UTF8.GetBytes((string)Data));
            }
            return Crc32.ComputeChecksum((byte[])Data);
        }

        public int CalculateSize() {
            if (Data is string) {
                return ((string)Data).Length;
            }
            return ((byte[])Data).Length;
        }

        public static GameState FromGame(Game game, bool forceBinary) {
            if (Message.UseXmlSerialization
                && !forceBinary) {
                XmlOutputArchive xmlOutputArchive = new(new XElement("Game"));
                xmlOutputArchive.Serialize(null, game);
                return new GameState { StepIndex = game.StepModule.StepIndex, Data = xmlOutputArchive.Node.ToString() };
            }
            MemoryStream memoryStream = new();
            BinaryOutputArchive binaryOutputArchive = new(memoryStream);
            binaryOutputArchive.Use7BitInts = true;
            binaryOutputArchive.Serialize(null, game);
            return new GameState { StepIndex = game.StepModule.StepIndex, Data = memoryStream.ToArray() };
        }

        public static Game ToGame(GameState state) {
            if (state.Data is string) {
                return new XmlInputArchive(XElement.Parse((string)state.Data)).Serialize<Game>(null);
            }
            return new BinaryInputArchive(new MemoryStream((byte[])state.Data)) { Use7BitInts = true }.Serialize<Game>(null);
        }
    }
}